import { vec3 } from 'gl-matrix';
import { OBJFile } from './OBJFile';

export async function loadObj(url: string) {
  const objResponse = await fetch(url);
  const objBody = await objResponse.text();

  const obj = await (async () => {
    return new Promise((resolve: (value: OBJFile) => void) => {
      const obj = new OBJFile(objBody);
      obj.parse();
      resolve(obj);
    });
  })();

  const positions: number[] = [];
  const normals: number[] = [];
  const indices: number[] = [];

  let minX = Number.MAX_VALUE;
  let maxX = Number.MIN_VALUE;

  let minY = Number.MAX_VALUE;
  let maxY = Number.MIN_VALUE;

  let minZ = Number.MAX_VALUE;
  let maxZ = Number.MIN_VALUE;

  for (const v of obj.result.models[0].vertices) {
    positions.push(v.x);
    positions.push(v.y);
    positions.push(v.z);
    normals.push(0.0);
    normals.push(0.0);
    normals.push(0.0);
  }

  //cs_start: normal_loading
  for (const f of obj.result.models[0].faces) {
    const points = [];
    const facet_indices = [];
    for (const v of f.vertices) {
      const index = v.vertexIndex - 1;
      indices.push(index);

      const x = positions[index * 3];
      const y = positions[index * 3 + 1];
      const z = positions[index * 3 + 2];

      const vertex = vec3.fromValues(x, y, z);

      minX = Math.min(x, minX);
      maxX = Math.max(x, maxX);

      minY = Math.min(y, minY);
      maxY = Math.max(y, maxY);

      minZ = Math.min(z, minZ);
      maxZ = Math.max(z, maxZ);

      points.push(vertex);
      facet_indices.push(index);
    }

    const v1 = vec3.subtract(vec3.create(), points[1], points[0]);
    const v2 = vec3.subtract(vec3.create(), points[2], points[0]);
    const cross = vec3.cross(vec3.create(), v1, v2);
    const normal = vec3.normalize(vec3.create(), cross);

    for (const i of facet_indices) {
      normals[i * 3] += normal[0];
      normals[i * 3 + 1] += normal[1];
      normals[i * 3 + 2] += normal[2];
    }
  }
  //cs_end: normal_loading

  return {
    positions,
    normals,
    indices,
    center: [(minX + maxX) * 0.5, (minY + maxY) * 0.5, (minZ + maxZ) * 0.5],
    radius: Math.max(Math.max(maxX - minX, maxY - minY), maxZ - minZ) * 0.5,
  };
}
